package edu.bu.cs673.superkids123;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;

import edu.bu.cs673.superkids123.children.controller.AchievementController;
import edu.bu.cs673.superkids123.children.model.Theme;
import edu.bu.cs673.superkids123.children.model.resources.ChildrenResource;
import edu.bu.cs673.superkids123.children.model.resources.ChildrenResourceProvider;
import edu.bu.cs673.superkids123.children.view.ChildProfileView;
import edu.bu.cs673.superkids123.common.model.Child;
import edu.bu.cs673.superkids123.common.model.User;
import edu.bu.cs673.superkids123.common.view.LoginView;
import edu.bu.cs673.superkids123.parents.view.ParentSettingsView;

/**
 * Class the defines the navigation configuration and how back/exit is handled by the main view
 * 
 * @author bhepburn
 * 
 */
public abstract class AbstractNavigationView extends AbstractView<JComponent> {
	// Only want 1 set of navigation fields
	private static JPanel panel;
	private static JPanel headerPanel; 
	private static JPanel bodyPanel;
	private static JPanel footerPanel;
	private static JButton backButton, avatarButton, parentsButton;
	private static JLabel titleLabel;
	private static TitledBorder titleBorder;

	private static final String CHILD_LABEL_TEXT_FORMAT = "<html><body><b>%s</b><br/>%s \u2605</body></html>";
	private static float AVATAR_SCALE = 0.75f;
	private static final int H_GAP = 20;
	private static final int V_GAP = H_GAP;
	private static final int HEADER_HEIGHT = 75;

	private static LinkedList<Class<? extends AbstractView<? extends JComponent>>> navHistory = new LinkedList<Class<? extends AbstractView<? extends JComponent>>>();

	private ChildrenResourceProvider provider = ChildrenResourceProvider.getInstance();

	/**
	 * Constructor for the AbstractNavigationView
	 * 
	 * @param mainFrame The main frame in which the views are contained
	 */
	public AbstractNavigationView(AbstractFrame mainFrame) {
		super(mainFrame);

		if (panel == null) {
			initializeNavigation();
		}
	}

	/**
	 * Abstract method to get title for the view to be shown in navigation view
	 * 
	 * @return The title of the view
	 */
	public abstract String getTitle();

	/**
	 * Abstract method to get border title for the view to be shown in navigation view
	 * 
	 * @return The border title for the view
	 */
	public abstract String getBorderTitle();

	/* 
	 * Overridden method to handle the navigation history
	 * 
	 * (non-Javadoc)
	 * @see edu.bu.cs673.superkids123.AbstractView#initializeView()
	 */
	protected AbstractView<? extends JComponent> initializeView() {
		super.initializeView();

		int index = navHistory.indexOf(this.getClass());
		if (index != -1) {
			// Pull the items off the top until we get to the view
			for (int i = 0; i < index; i++)
				navHistory.pop();
		} else {
			// Only push on history if not in the list
			navHistory.push(this.getClass());
		}

		return this;
	}

	/* 
	 * Overridden method to show the navigation layout and the current views content
	 * 
	 * (non-Javadoc)
	 * @see edu.bu.cs673.superkids123.AbstractView#getContentPane()
	 */
	protected JComponent getContentPane() {
		// Get the content
		JComponent content = layout();

		// Update UI elements
		updateUIElements();

		// Add the content
		bodyPanel.removeAll();
		bodyPanel.add(content);
		bodyPanel.validate();
		bodyPanel.repaint();

		return panel;
	}

	/**
	 * Method to update the navigation elements based on the input data.
	 */
	protected void updateUIElements() {
		titleLabel.setText(getTitle());
		titleBorder.setTitle(getBorderTitle());

		if (navHistory.size() == 1) {
			backButton.setIcon(provider.getImage(ChildrenResource.imageIconX));
			backButton.setText("Exit");
		} else {
			backButton.setIcon(provider.getImage(ChildrenResource.imageIconBack));
			backButton.setText("Back");
		}
	}

	/**
	 * Initializes all the navigation components
	 */
	public void initializeNavigation() {
		// View
		panel = new JPanel(new BorderLayout(H_GAP, V_GAP));
		panel.setBorder(new EmptyBorder(V_GAP, H_GAP, V_GAP, H_GAP));

		// Header
		headerPanel = new JPanel(new BorderLayout());
		headerPanel.setOpaque(false);
		backButton = new JButton("Exit");
		backButton.setIcon(provider.getImage(ChildrenResource.imageIconX));
		backButton.setFont(Theme.CHILD_FONT_SMALL);
		backButton.setVerticalTextPosition(JButton.BOTTOM);
		backButton.setHorizontalTextPosition(JButton.CENTER);
		backButton.setPreferredSize(new Dimension(31, HEADER_HEIGHT));
		backButton.setBorder(BorderFactory.createEmptyBorder());
		backButton.setContentAreaFilled(false);
		backButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// Call the actionPerformed in the navigation view
				processBackEvent(e);
			}
		});

		titleLabel = new JLabel("Title");
		titleLabel.setFont(Theme.CHILD_FONT_LARGE);
		titleLabel.setHorizontalAlignment(SwingConstants.CENTER);

		avatarButton = new JButton("Avatar");
		avatarButton.setHorizontalTextPosition(JButton.LEADING);
		avatarButton.setContentAreaFilled(false);
		avatarButton.setVisible(false);
		avatarButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// Call the actionPerformed in the navigation view
				processAvatarEvent(e);
			}
		});

		headerPanel.add(backButton, BorderLayout.WEST);
		headerPanel.add(titleLabel, BorderLayout.CENTER);
		headerPanel.add(avatarButton, BorderLayout.EAST);

		// Body
		titleBorder = BorderFactory.createTitledBorder("Titled Border");
		titleBorder.setTitleFont(Theme.CHILD_FONT_SMALL);
		bodyPanel = new JPanel(new GridLayout(1, 1));
		bodyPanel.setBorder(titleBorder);
		panel.add(bodyPanel, BorderLayout.CENTER);

		// Footer
		parentsButton = new JButton("Parents");
		parentsButton.setIcon(provider
				.getImage(ChildrenResource.imageIconSettings));
		parentsButton.setVerticalTextPosition(JButton.BOTTOM);
		parentsButton.setHorizontalTextPosition(JButton.CENTER);
		parentsButton.setFont(Theme.CHILD_FONT_SMALL);
		parentsButton.setBorder(BorderFactory.createEmptyBorder());
		parentsButton.setContentAreaFilled(false);
		parentsButton.setVisible(false);
		parentsButton.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				processParentButtonEvent(e);
			}
		});

		footerPanel = new JPanel(new BorderLayout());
		footerPanel.add(parentsButton, BorderLayout.EAST);

		// Add to layout
		panel.add(headerPanel, BorderLayout.PAGE_START);
		panel.add(footerPanel, BorderLayout.PAGE_END);
	}

	/**
	 * This method processes the back button event for the navigation view
	 * 
	 * @param e The event triggered by the listener
	 */
	public void processBackEvent(ActionEvent e) {
		Object source = e.getSource();
		if (source.equals(backButton)) {

			if (navHistory.size() == 1) {
				getMainFrame().exit();
				return;
			} else {
				Class<? extends AbstractView<? extends JComponent>> view = null;
				// Check to see if top of nav is the current item in history
				while (navHistory.peek()
						.equals(getMainFrame().getCurrentView())) {
					// Pull the element off the top to try to get to previous
					view = navHistory.pop();
				}

				// Switch to previous view
				if (!getMainFrame().changeView(navHistory.peek())
						&& view != null) {
					// If the switch fails because of initialize push view back
					// on
					navHistory.push(view);
				}
			}
		}
	}

	/**
	 * This method processes the parent button event
	 * 
	 * @param e the event triggered by the action listen
	 */
	public void processParentButtonEvent(ActionEvent e) {
		Object source = e.getSource();
		if (source.equals(parentsButton)) {
			if (authController.getCurrentUser() != null) {
				if (getMainFrame().changeView(LoginView.class))
					getMainFrame().changeView(ParentSettingsView.class);
			} else {
				getMainFrame().changeView(ParentSettingsView.class);
			}
		}
	}

	
	/**
	 * Method that will enable/disabled the parents button
	 * 
	 * @param visible whether or not to show the parents button
	 */
	public void setParentsButtonVisible(boolean visible) {
		parentsButton.setVisible(visible);
	}

	/**
	 * Method that processes the click of the avatar icon
	 * 
	 * @param The event that is triggered by the listener
	 */
	private void processAvatarEvent(ActionEvent e) {
		Object source = e.getSource();
		if (source.equals(avatarButton)) {
			getMainFrame().changeView(ChildProfileView.class);
		}
	}
	
	/**
	 * Method that will enable/disable the avatar icon
	 * 
	 * @param visible whether or not to show the avatar icon
	 */
	public void setAvatarVisible(boolean visible) {
		avatarButton.setVisible(visible);

		if (visible) {
			User user = authController.getCurrentUser();
			if (user instanceof Child) {
				Child child = (Child) user;
				avatarButton.setIcon(provider.getScaledImage(child.getImage()
						.getFileName(), AVATAR_SCALE));
				int points = getMainFrame().getController(AchievementController.class).getPoints();
				String text = String.format(CHILD_LABEL_TEXT_FORMAT, child.getName(), points); 
				avatarButton.setText(text);
				avatarButton.setBorder(BorderFactory.createEmptyBorder());
			}
		}
	}

	
	/**
	 * Method that will enable/disabled the title border
	 * 
	 * @param visible whether or not to show the title border
	 */
	protected void setTitleBorderVisible(boolean visible) {

		if (visible) {
			bodyPanel.setBorder(titleBorder);
		} else {
			bodyPanel.setBorder(new EmptyBorder(V_GAP, H_GAP, V_GAP, H_GAP));
		}
	}
}


